/* 算法实现模板 */
import AlgorithmBase from "./AlgorithmBase";
import { mdRender} from "../../../common/Common";
import {KDNode,createKDNode,NodeRange,calcNodeRange} from "../../../common/KDTreeFuncs";
import {toKatexString,toVector} from "../../../common/Vector";
import Figure2D from "../../../visual/Figure2D";
import {drawKDTree} from "../../../visual/Tree2D";
import 'katex/dist/katex.min.css';

class KDTree extends AlgorithmBase{
  constructor(){
    super('KDTree');

    this.descriptionUrl = `${this.homepage}/data/slm/ch3/README3.2.md`;
    this.datasetUrl     = `${this.homepage}/data/slm/ch3/dataset.json`;
    const figure = new Figure2D(600, 450);
    figure.xMax = 10.0;
    figure.xMin = 0.0;
    figure.yMax = 10.0;
    figure.yMin = 0.0;
    figure.gridX = 12;
    figure.gridY = 12;
    this.figure = figure;
  }

  init(){ 
    this.reset();
    if(this.trainLogDiv) {
      this.trainLogDiv.innerHTML = '';
      this.trainLogDiv.appendChild(this.figure.domElement);
    }
    this.initTrainDS();
  }

  reset(){
    this.dataset = undefined;
    this.trainDS = undefined;
    this.model = {node:[]};
    this.clear();
    this.initDescription();
    this.updateModel();
  }


  loadModel(json){
    if(json.TrainDS){
      this.trainDSList = [];
      if(json.TrainDS instanceof Array){
        for(let i = 0, il = json.TrainDS.length; i < il; i++){
          const newTrain = json.TrainDS[i];
          newTrain.T = toVector(newTrain.T, true);
          this.trainDSList.push(newTrain);
        }
        this.trainDS = this.trainDSList[0];
      }
      else{
        this.trainDS.dataset = toVector(json.TrainDS.T, true);
      }
    }
    this.model.node = new KDNode();
    return this.trainDS;
  }

  initDescription(){
    fetch(this.descriptionUrl).then((response)=>{
      return response.text();
    }).then((txt)=>{

      this.reandMD(txt, this.descriptionDiv)
    })
  }
  
  initTrainDS(){
    this.prepare(this.datasetUrl);
  }


  // 准备数据训练数据
  prepare(url){
    fetch(url).then((response)=>{
      return response.json();
    }).then((json)=>{
      this.trainDS = this.loadModel(json);
      this.updateModel();
    })
  }

  openFileSelector(){
    this.fileSelector.click();
  }

  // 获取文件路径加载
  handleFileChange(event){
    const files = event.target.files;

    for(let i = 0, il = files.length; i < il; i++){
      let reader = new FileReader();
      reader.onload = (e) => {      
        this.prepare(e.target.result);
        if(i === files.length - 1){
          event.target.value = '';
        }
      };
      reader.readAsDataURL(files[i])
    }
  }

   // 输入数据UI
   initInputUI(){

    // 文件选择器
    const fileSelector      = document.createElement('input');
    fileSelector.type       = 'file';
    fileSelector.hidden     = true;
    fileSelector.onchange   = this.handleFileChange.bind(this);   
    
    this.addButton(this.domElementList.input, "获取服务器数据", this.initTrainDS.bind(this));
    this.addButton(this.domElementList.input, "使用本地数据", this.openFileSelector.bind(this));
    this.domElementList.input.appendChild(fileSelector);
    this.addButton(this.domElementList.input, "训练", this.train.bind(this));
    this.labelTrainTips = this.addLabel(this.domElementList.input, '');
    this.inputDiv       = this.addDiv(this.domElementList.input);
    this.fileSelector  = fileSelector;
  }

  // 输出UI
  initOutputUI(){
    this.outputDiv   = this.addDiv(this.domElementList.output);
    this.trainLogDiv = this.addDiv(this.domElementList.output);
    
  }


  drawSplitLine(node){
    if(!node || !node.dom_elt) return;
    
    const dom_elt = node.dom_elt;
    if(!this.figure) return;
    
    if(node.split === 0){
      this.figure.addLine([dom_elt[0], node.sMin], [dom_elt[0], node.sMax]);
    }
    else{
      this.figure.addLine([node.sMin, dom_elt[1]], [node.sMax, dom_elt[1]]);
    }

    this.drawSplitLine(node.left);
    this.drawSplitLine(node.right);

    this.figure.update();

  }

  displayModel(){
    let node = this.model.node;
    
    if(this.figure){
      let range = new NodeRange([[this.figure.xMin, this.figure.xMax + 1],[this.figure.yMin,this.figure.yMax + 1]]);

      calcNodeRange(node, range);
      // 绘制分割线
      this.drawSplitLine(node);
      this.figure.update();
    }

    if(this.outputDiv) this.outputDiv.innerHTML = '';
    drawKDTree(this.outputDiv, node);
  }


  train(){
    const T = this.trainDS.T;
    let node = createKDNode(0, T);
    this.model.node = node;
    // if(this.figure) this.figure.clearAll();
    this.displayModel();
  }


  updateModel(data){
    // 显示数据集
    if(this.trainDS){
      if(data === undefined) data = this.trainDS.T;
      let katexString = String.raw`\{`;
      for(let i = 0, il = data.length; i < il; i++){
        katexString += data[i].toKatexString();
        if(i !== il - 1){
          katexString += ',';
        }
        if(this.figure){
          const point = data[i];
          if(point.length === 2){
            this.figure.addPoint(point[0], point[1]);
          }
        }
      }
      katexString += String.raw`\}`;
      mdRender(`${katexString}`, this.inputDiv)
    }
    // 绘制点到图
    if(this.figure){
      this.figure.update();
    }
}

}
export default KDTree;